<?php
// Connections
$c = new Mongo();
$db = 'blog';
$conn = $c->$db;
MongoCursor::$timeout = -1;

$authors_col = 'authors';
$posts_col = 'posts';

//The main query function - reduces redudant code
function q($col='') {
	global $conn;
	if($col == 'post' || ($col == 'posts')) {
		$col = 'posts';
	} elseif($col == 'author' || ($col == 'authors')) {
		$col = 'authors';
	} else {
		$col = $col;
	}
	return ($col == '') ? $conn : $conn->$col;
}

// Function to generate random posts
function Posts() {
	$post = array(
		'author' => MongoDBRef::create('authors', pickRandomID()),
		'post' => description(),
		'post_title' => postTitle(),
		'date' => Ttime(),
		'rating' => rand_Int(0,10),
		'comments' => randComments(),
		'tags' => rand_Tags(array('politics', 'Denmark', 'America', 'War', 'Obama', 'Staten Island', '9/11', 'World War II', 'world War I', 'Freedom', 'Martin Luther King'))
	);
	return $post;
}

// Creates the author in the authors collection
function createAuthor($i) {
$author = array(
			'name' => parseNames($i),
			'email' => strtolower(realname('mail') . "@" . rand_URL() . rand_Text(array('.com', '.net', '.dk', '.info', '.org'))),
			'age' => rand_Int(12,99),
			'city'	=> rand_Text(array('Copenhagen','London','Stockholm','Oslo','Madrid','Roma','Berlin', 'New York', 'Mexico City', 'Denver', 'Houston', 'Seattle', 'Ankara', 'Athen'))
		);
	return $author;
}

// Function to pick a random author ID to use in a blog post document as reference
function pickRandomID() {
	global $authors_col;
	$authorID = array();
	$cursor = q('author')->find()->fields(array('_id' => 1));
	while ($cursor->hasNext()): $document = $cursor->getNext();
		$authorID[] = $document['_id'];
	endwhile;

	$aid = $authorID[array_rand($authorID)];
	return $aid;
}

// Function to get all blog post documents _id
function pickRandDoc() {
	$authorID = array();
	$cursor = q('posts')->find()->fields(array('_id' => 1));
	while ($cursor->hasNext()): $document = $cursor->getNext();
		set_time_limit(0);
		ini_set("memory_limit","500M");
		$authorID[] = $document['_id'];
	endwhile;
	return $authorID;
}

/* 	
	BASIC GENERATOR FUNCTIONS
	These functions is used for powering the random post and author generator
*/

function rand_Large() {
	$ran1 = mt_rand();
	$ran2 = mt_rand();
	$randomInt = $ran1.$ran2;
	return $randomInt;
}

function rand_tf() {
	$tf_int = rand(0,1);
	if($tf_int == 0) {
		$state = 'false';
	} else {
		$state = 'true';
	}
	return $state;
}

function rand_Text($words) {
	return $words[array_rand($words)];
}

function rand_Tags($tags) {
	$randTags = array_rand($tags, 2);
	
	$tag1 = $tags[$randTags[0]];
	$tag2 = $tags[$randTags[1]];
	$combine = array($tag1, $tag2);

	return $combine;
}

function rand_URL() {
	$filename = "misc_gen/urls.txt";

	$lines = file($filename) ; 
	return $lines[array_rand($lines)] ; 
}

function Ttime() {

	$ranTime = mt_rand(788918400, 1335830400);
	return $ranTime;
}

function realname($type='name') {
	$i = rand(0,4);
	if ($i % 2 == 0) {
		$file_content = file_get_contents("realname_gen/female_surname.csv");
		$file_content_separated_by_spaces = explode("\n", $file_content);
		$rand = $file_content_separated_by_spaces[array_rand($file_content_separated_by_spaces)];
	} else {
		$file_content = file_get_contents("realname_gen/male_surname.csv");
		$file_content_separated_by_spaces = explode("\n", $file_content);
		$rand = $file_content_separated_by_spaces[array_rand($file_content_separated_by_spaces)]; 
	}

	if($i % 2 == 0) {
		$file_content3 = file_get_contents("realname_gen/lastname.csv");
		$file_content_separated_by_spaces3 = explode("\n", $file_content3);
		$rand2 = $file_content_separated_by_spaces3[array_rand($file_content_separated_by_spaces3)]; 
	} else {
		$file_content4 = file_get_contents("realname_gen/lastname_2.csv");
		$file_content_separated_by_spaces4 = explode("\n", $file_content4);
		$rand2 = $file_content_separated_by_spaces4[array_rand($file_content_separated_by_spaces4)]; 
	}

	if($type == 'name') {
		return $rand. " " . $rand2;
	} else {
		return $rand. "_" . $rand2;
	}
}

function parseNames($i) {
	$getNames = file_get_contents("realname_gen/randomNames_fixed.csv");
	$getNames = explode("\n", $getNames);
	return $getNames[$i];
}

function rand_Int($min=0, $max=99999) {
	return mt_rand($min,$max);
}

function description() {
	$i = rand(0,10);
	if ($i % 2) {
		$file_content = file_get_contents("description_gen/desc_rand_01.csv");
		$file_content_separated_by_spaces = explode("\n", $file_content);
		$rand = $file_content_separated_by_spaces[array_rand($file_content_separated_by_spaces)]; 
	} else {
		$file_content = file_get_contents("description_gen/desc_rand_02.csv");
		$file_content_separated_by_spaces = explode("\n", $file_content);
		$rand = $file_content_separated_by_spaces[array_rand($file_content_separated_by_spaces)]; 
	}

	$file_content3 = file_get_contents("description_gen/desc_rand_03.csv");
	$file_content_separated_by_spaces3 = explode("\n", $file_content3);
	$rand3 = $file_content_separated_by_spaces3[array_rand($file_content_separated_by_spaces3)]; 

	return $rand. " " . $rand3;
}

function postTitle() {
	$randomPostTitle = file_get_contents("misc_gen/post_title.csv");
	$randomPostTitle_separated_by_spaces = explode("\n", $randomPostTitle);
	$randomPostTitleForMongo = $randomPostTitle_separated_by_spaces[array_rand($randomPostTitle_separated_by_spaces)]; 
	
	return ucfirst($randomPostTitleForMongo);
}

function randComments() {
$comments = array();

$commentCount = rand_Int(1,10);

	for($i=0; $i<$commentCount; $i++) {
		$comments[] = array(
			'name' => realname(),
			'email' => realname('mail') . "@" . rand_Text(array('.com', '.net', '.dk', '.info', '.org')),
			'upVotes' => rand_Int(0, 100),
			'downVotes' => rand_Int(0, 100),
			'comment_date' => Ttime(),
			'comment' => description()
		);
	}
	return $comments;
}

/* 	
	END BASIC GENERATOR FUNCTIONS
*/

/* BASIC USEAGE FUNCTIONS THROUGHOUT THE TEST AND IMPLEMENTATION */

function redirect_to( $location = NULL ) {
	if ($location != NULL) {
		header("Location: {$location}");
		exit;
	}
}

// write output to file
function dump_to_file($obj, $filename, $mode='a') {
	if($mode != '' && (!empty($mode))) {
		if($mode != 'w' || ($mode != 'a')) {
			$mode == 'a';
		}
	}
	$file = $filename;
	$path = 'files/'.$file;
	$fh = fopen($path, $mode) or die("can't open file");
	fwrite($fh, $obj."\n");
	fclose($fh);	
	return;
}

// Time function
function timeit() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

// Log function
function l($title='', $time=0) {
	dump_to_file($title, 'log.dat', 'a');
}

// Log function 2
function l2($title='', $time=0) {
	dump_to_file($title.": Time: " . date("d / m - Y H:i:s", time()) . " | Running time:\n" . $time."\n", 'log.dat', 'a');
}

// Correct sorting
function correctSort (&$array, $key) {
    $sorter=array();
    $ret=array();
    reset($array);
    foreach ($array as $ii => $va) {
        $sorter[$ii]=$va[$key];
    }
    asort($sorter);
    foreach ($sorter as $ii => $va) {
        $ret[$ii]=$array[$ii];
    }
    $array=$ret;
	return $array;
}

/* END BASIC USEAGE FUNCTIONS THROUGHOUT THE TEST AND IMPLEMENTATION */

/* THE QUERY ENGINE FOR TESTS */

function query($q) {
	$regex = new MongoRegEx('/lorem ipsum/i');
	$regex2 = new MongoRegEx('/lorem ipsum/');
	$regex3 = new MongoRegEx('/^lorem ipsum/');
	
	switch($q) {
		case 'q1.1':
			$log = 'RegEx - Full Text Search on both post and post title';
			$query = array('post' => $regex);
			$start = timeit();
			$cursor = q('post')->find($query);
			
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;

		case 'q1.1.1':
			$log = 'RegEx - Full Text Search on both post and post title';
			$query = array('post' => $regex2);
			$start = timeit();
			$cursor = q('post')->find($query);
			
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;	

		case 'q1.1.2':
			$log = 'RegEx - Full Text Search on both post and post title with prefix';
			$query = array('post' => $regex3);
			$start = timeit();
			$cursor = q('post')->find($query);
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;	
			
		case 'q1.2':
			$log = 'RegEx - Full Text Search on both post and post title, sorted by date descending';
			$query = array('post' => $regex);
			$start = timeit();
			$cursor = q('post')->find($query)->sort(array('date' => -1));
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);

			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'q2.1':
			$log = 'Find rating higher than 15, and less than or equal to 22, and tags which is either War or Polictics';
			$query = array('rating' => array('$gt' => 3, '$lte' => 7), 'tags' => array('$in' => array('war', 'politics')));
			$start = timeit();
			$cursor = q('post')->find($query);
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);	
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'q2.2':
			$log = 'Find rating higher than 15, and less than or equal to 22, and tags which is either War or Polictics, sorted by rating descending and date ascending';
			$query = array('rating' => array('$gt' => 3, '$lte' => 7), 'tags' => array('$in' => array('war', 'politics')));
			$start = timeit();
			$cursor = q('post')->find($query)->sort(array('rating'=>-1, 'date'=>1));
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);	
			
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'insert':
			$start = timeit();
			q('post')->insert(Posts());
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);
			
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'delete':
			$id = array('_id' => new MongoId(pickRandomID()));
			$ops = array('justOne' => true);
			$start = timeit();
			q('post')->remove($id, $ops);
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);
			
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'update':
			$array = array();
			// To make sure that the post title and content does not breaks the JSON formattation, we add the PHP function addslashes before assigning it to the array.
			$array['post_title'] = addslashes(postTitle());
			$array['post_content'] = addslashes(description());
			$array['tags'] = rand_Tags(array('politics', 'Denmark', 'America', 'War', 'Obama', 'Staten Island', '9/11', 'World War II', 'world War I', 'Freedom', 'Martin Luther King'));
			
			$id = new MongoId(pickRandomID());
			
			$start = timeit();
			q('post')->update(array('_id' => $id), array('$set' => $array));
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);
			
			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'insert_safe':
			$start = timeit();
			$ops = array('safe' => true, 'fsync' => true);
			q('post')->insert(Posts(), $ops);
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);

			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'delete_safe':
			$id = array('_id' => new MongoId(pickRandomID()));
			$ops = array('justOne' => true, 'safe' => true, 'fsync' => true);
			$start = timeit();
			q('post')->remove($id, $ops);
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);

			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
			
		case 'update_safe':
			$array = array();
			// To make sure that the post title and content does not breaks the JSON formattation, we add the PHP function addslashes before assigning it to the array.
			$array['post_title'] = addslashes(postTitle());
			$array['post_content'] = addslashes(description());
			$array['tags'] = rand_Tags(array('politics', 'Denmark', 'America', 'War', 'Obama', 'Staten Island', '9/11', 'World War II', 'world War I', 'Freedom', 'Martin Luther King'));
			
			$id = new MongoId(pickRandomID());
			$ops = array('safe' => true, 'fsync' => true);
			$start = timeit();
			q('post')->update(array('_id' => $id), array('$set' => $array), $ops);
			$end = timeit();
			$time = number_format($end - $start, 15);
			l($time);

			// RESET TIME VARIABLES
			unset($start);
			unset($end);
			break;
	}
}

function index($col, $args, $ops='create') {

	// CREATE INDEX ON POST
	if(!is_array($args)) {
		echo "The index variable must be an array";
	} else {
		$start = timeit();
		$cursor = q($col)->ensureIndex($args);
		$end = timeit();
		$time = number_format($end - $start, 15);
		l('CREATE INDEX ON FIELDS: '.strtoupper(implode(", ", array_keys($args))), $time);
	}
}

function avg($arr){
	$sum = array_sum($arr);
	$num = count($arr);
	return number_format($sum/$num, 15);
}
?>

